package com.xm.utils.common;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;

public class CollectionUtil {

    /**
     * 更好用的分组
     * <p>
     * <p>
     * eg: Order 类有两个字段，orderNo, memberNo(会员号)
     * 按会员号分组获取订单号
     * List<Order> data = new ArrayList<>();
     * List<String> orderNoList = CollectionUtil.group(data,Order::getMemberNo,Order::getOrderNo);
     *
     * @param data
     * @param keyFun
     * @param valueFun
     * @param <R>
     * @param <K>
     * @param <V>
     * @return
     */
    public static <R, K, V> Map<K, List<V>> group(Collection<R> data, Function<R, K> keyFun, Function<R, V> valueFun) {
        Map<K, List<V>> group = new HashMap<>();
        data.forEach(e -> group.computeIfAbsent(keyFun.apply(e), k -> new ArrayList<>())
                .add(valueFun.apply(e)));
        return group;
    }

    /**
     * 去重的分组
     *
     * @param data
     * @param keyFun
     * @param valueFun
     * @param <R>
     * @param <K>
     * @param <T>
     * @return
     */
    public static <R, K, T> Map<K, Set<T>> distinctGroup(Collection<R> data, Function<R, K> keyFun, Function<R, T> valueFun) {
        Map<K, Set<T>> group = new HashMap<>();
        data.stream()
                .distinct()
                .forEach(e -> group.computeIfAbsent(keyFun.apply(e), k -> new HashSet<>())
                        .add(valueFun.apply(e)));
        return group;
    }

    /**
     * 向分组数据里面加入数据，
     * 如果存在对应的分组list，则追加到list里，
     * 否则新建一个list,然后追加数据
     * <p>
     * eg: Order 类有两个字段，orderNo, memberNo(会员号)
     * 已有一个按会员号分组数据的分组订单数据 Map<String,List<Order>> group;
     * 现在要往group中添加一个订单 order
     * <p>
     * CollectionUtil.addForGroup(group,order.getMemberNo(),order);
     *
     * @param group
     * @param k
     * @param v
     * @param <K>
     * @param <V>
     */
    public static <K, V> void addForGroup(Map<K, List<V>> group, K k, V v) {
        List<V> list = group.computeIfAbsent(k, k1 -> new ArrayList<>());
        list.add(v);
    }
}
